#include "vsGlobal.h"
#include <math.h>
#include <QFileInfo>
#include <QTime>

Q_GLOBAL_STATIC(vsLog, vslog_instance)

vsLog* vsLog::instance()
{
    return vslog_instance();
}

vsLog::~vsLog() {}

void vsLog::i(const QString &msg) { vslog_instance()->addMessage(msg, vsLog::info);   }
void vsLog::d(const QString &msg) { vslog_instance()->addMessage(msg, vsLog::debug);  }
void vsLog::e(const QString &msg) { vslog_instance()->addMessage(msg, vsLog::error);  }
void vsLog::s(const QString &msg) { vslog_instance()->addMessage(msg, vsLog::success);}
void vsLog::n()                   { vslog_instance()->addMessage("",  vsLog::none);   }

void vsLog::r(const QString &msg) { vslog_instance()->reemit(msg); }

void vsLog::addMessage(QString msg, vsLog::msgType type)
{
    if (type == vsLog::none)
        msg = " ";
    else
    {
#ifdef DEBUG
        qDebug() << msg;
#endif

        msg.prepend("\t");
        QString time = QTime::currentTime().toString();

        if (time.compare(lastTime) != 0)
        {
            msg.prepend(time);
            lastTime = time;
        }
    }

    emit message(msg, type);
    history.append(QString("%1%2").arg((int)type).arg(msg));
}

void vsLog::reemit(QString msgFromHistory)
{
    emit message(msgFromHistory.remove(0,1), (vsLog::msgType)msgFromHistory.left(1).toInt());
}

QString durationToString(qint64 msec)
{
    qint64 totalSeconds = msec / 1000;
    int seconds = totalSeconds % 60;
    int minutes = floor(totalSeconds / 60.f);
    return QString().sprintf("%i:%02i", minutes, seconds);
}


const qint64 _KBi = 1024;
const qint64 _MBi = _KBi * 1024;
const qint64 _GBi = _MBi * 1024;
const qint64 _TBi = _GBi * 1024;

const double _KBf = _KBi;
const double _MBf = _MBi;
const double _GBf = _GBi;
const double _TBf = _TBi;

const QString _Bs  = QObject::tr("B");
const QString _KBs = QObject::tr("KB");
const QString _MBs = QObject::tr("MB");
const QString _GBs = QObject::tr("GB");
const QString _TBs = QObject::tr("TB");


QString sizeToString(qint64 bytes)
{
    if (bytes > _KBi)
        if (bytes > _MBi)
            if (bytes > _GBi)
                if (bytes > _TBi) return QString().sprintf("%.2f ", bytes/_TBf) + _TBs;
                else              return QString().sprintf("%.2f ", bytes/_GBf) + _GBs;
            else                  return QString().sprintf("%.2f ", bytes/_MBf) + _MBs;
        else                      return QString().sprintf("%.2f ", bytes/_KBf) + _KBs;
    else                          return QString().sprintf("%i ",   (int)bytes) + _Bs;
}

QString genID()
{
    static int i = 0;
    return QString("id%1").arg(i++);
}

bool checkID(const QString &id)
{
    static QRegExp re(c_vctb_id_re);
    return id.length() > 1 && id.length() <= c_vctb_id_max_length && re.exactMatch(id);
}

QString urlEncodedName(const QString &name)
{
    QFileInfo fi(name);
    QString n = fi.fileName();

    if (!fi.suffix().isEmpty())
    {
        int extLen = fi.suffix().length() + 1; // + '.'
        n.remove(n.length() - extLen, extLen);
    }

    n.replace(' ', '+');
    n.replace(QRegExp("[&/\\\\:$\"\t\r\n]"), "-");

    return n;
}

QList<QPair<qint64,qint64> > splitFileByteRange(qint64 from, qint64 count, qint64 fileSize, int &firstIndex)
{
    assert(from >= 0 && count > 0 && from + count <= fileSize);
    QList<QPair<qint64,qint64> > result;

    if (fileSize < c_file_part_size*2) // if file isn't large enough to be cached in more than one part
        result << QPair<qint64,qint64>(from, count);
    else
    {
        int parts = fileSize / c_file_part_size;
            firstIndex = from / c_file_part_size;
        int lastIndex  = (from + count) / c_file_part_size;

        if (firstIndex >= parts)
            firstIndex--; // last part's length is in range [file_part_size..file_part_size*2)

        if (lastIndex >= parts)
            lastIndex--;

        if (firstIndex == lastIndex)
            result << QPair<qint64,qint64>(from, count);
        else
        {
            // first
            result << QPair<qint64,qint64>(from, (firstIndex + 1) * c_file_part_size - from);

            // intermediates, if any (won't do a single cycle if last is first+1, e.g. no intermediate parts)
            for (int i = firstIndex + 1; i < lastIndex; ++i)
                result << QPair<qint64,qint64>(i * c_file_part_size, c_file_part_size);

            // last
            result << QPair<qint64,qint64>(lastIndex * c_file_part_size,
                                           from + count - lastIndex * c_file_part_size);
        }
    }

    return result;
}


QString wittyServeRefusal()
{
    int roll = (double)rand() / RAND_MAX * 100.f;   // when in doubt, roll d20

    if (roll < 20)  return QObject::tr("I-it's not like I wanted to serve you streams, you baka.");
    if (roll < 30)  return QObject::tr("No fancy streams for you, sir.");
    if (roll < 40)  return QObject::tr("Because just no.");
    if (roll < 60)  return QObject::tr("Being a multimedia server is suffering.");
    if (roll < 70)  return QObject::tr("And so it goes.");
    if (roll < 80)  return QObject::tr("Try better next time.");
    if (roll < 90)  return QObject::tr("Stop right there, criminal scum!");

    return                 QObject::tr("I'm not your typical Apache, you know.");
}


//-------------------------------------------------------------

byterateCounter::byterateCounter(int historyLength) : virtValues(0)
{
    if (historyLength <= 0)
    {
        historyLength = c_byterate_depth_max;
        vsLog::e("byterate counter: subzero history length, resetting to default");
    }

    if (historyLength >= 1000000)
    {
        historyLength = c_byterate_depth_max;
        vsLog::e("byterate counter: insane history length, resetting to default");
    }

    histLen = historyLength;
}

void byterateCounter::add(qint64 bytes)
{
    assert(bytes >= 0);

    if (history.isEmpty())
        append(bytes);
    else
    {
        history.last() += bytes;

        if (virtValues == history.size())
            --virtValues; // last isn't virtual anymore
    }
}

void byterateCounter::append(qint64 bytes)
{
    assert(bytes >= 0);

    history.append(bytes);

    while (history.size() > histLen)
        history.pop_front();

    if (virtValues > 0)
    {
        --virtValues;
        history.pop_front();
    }
}

qint64 byterateCounter::rate()
{
    qint64 sum = 0;

    if (!history.isEmpty())
    {
        QLinkedListIterator<qint64> i(history);
        sum = history.first();

        while (i.hasNext())
            sum += i.next();

        sum /= (qint64)history.size();
    }

    return sum;
}

void byterateCounter::minimize()
{
    while (history.size() > c_byterate_depth_min)
        history.pop_front();

    /* virtual values are used to gradually replace minimized list with real values
       without increasing its size before all values will be real (added after minimizing)
       so first 3 appends into list, minimized to size 3, won't increase its size */
    virtValues = c_byterate_depth_min;
}

//---------------------------------------
QString ipServiceTemplate;

void setIPService(const QString &ipsT) { ipServiceTemplate = "<a href=\"" + ipsT + "\">%1</a>"; }
QString getIPServiceTemplate()         { return ipServiceTemplate; }
//---------------------------------------
